package server.net;

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

/**
 *
 * @author Danon
 */
public class RequestQueue {
    
    private RequestQueue() {
        queue = new PriorityQueue<Request>(1000, new Comparator<Request>() {

            @Override
            public int compare(Request o1, Request o2) {
                if(o1==null && o2==null) return 0;
                if(o1==null) return -1;
                if(o2==null) return 1;
                if(o1 instanceof Request && o2 instanceof Request) {
                    if(o1 instanceof OrderRequest) {
                        if(o2 instanceof OrderRequest)
                            return o1.getId()-o2.getId();
                        else return -1;
                    } else if(o2 instanceof OrderRequest)
                        return 1;
                    else return o1.getId()-o2.getId();
                } else throw new IllegalArgumentException();
            }
        });
    }
    
    public static RequestQueue getInstance() {
        synchronized(instance) {
            if(instance == null)
                instance = new RequestQueue();
            return instance;
        }
    }
    
    public void handleSocket(Socket s) {
        Logger.getLogger(RequestQueue.class.getName()).log(Level.INFO, 
                "New connection from {0}", 
                s!=null? s.getInetAddress().toString() : null);
        SocketHandler h = new SocketHandler(s);
        h.start();
    }
    
    
    public final Request pop() {
        synchronized(instance) {
            return queue.poll();
        }
    }
    
    public void push(Request r) {
        synchronized(instance) {    
            queue.add(r);
        }
    }
    
    public void clear() {
        synchronized(instance) {
            queue.clear();
        }
    }
    
    public final int size() {
        synchronized(instance) {
            return queue.size();
        }
    }
    
    private static RequestQueue instance;
    private PriorityQueue<Request> queue;
}


class SocketHandler extends Thread {

    public SocketHandler(Socket s) {
        socket = s;
    }
    
    
    @Override
    public void run() {
        if(socket==null) return;
        Request r = extractRequest(socket);
        try {
            socket.close();
        } catch (IOException ex) {}
        RequestQueue.getInstance().push(r);
    }
    
    private Request extractRequest(Socket s) {
        if(s==null) return null;
        Request r = null;
        try{
            InputStream inputStream = s.getInputStream();
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse(inputStream);
            Node root = doc.getDocumentElement();
            NamedNodeMap map =  root.getAttributes();
            String type = map.getNamedItem("type").getTextContent();
            if("order".equals(type))
                r = OrderRequest.createFromDOM(doc);
            else if("circuit".equals(type))
                r = CircuitRequest.createFromDOM(doc);
        } catch (Exception ex) {
            return null;
        }
        return r;
    }
    
    private final Socket socket;
}
